package dpos

import (
	"hundsun.com/hsl/hschain/consensus/common"
	"hundsun.com/hsl/hschain/consensus/impl/dpos/checker"
	dposcommon "hundsun.com/hsl/hschain/consensus/impl/dpos/common"
	"hundsun.com/hsl/hschain/consensus/impl/dpos/miner"
	"hundsun.com/hsl/hschain/consensus/impl/dpos/selector"
	"hundsun.com/hsl/hschain/consensus/types"
	"hundsun.com/hsl/hschain/module"
	"hundsun.com/hsl/hschain/module/registry"
	protosconfig "hundsun.com/hsl/hschain/protos/config"
)

func init() {
	common.RegConsensus(types.ConsensusTypeDpos, NewDpos)
}

// Module dpos类型共识模块
type Module struct {
	module.Adapter
	types.ConsensusStatus

	selector *selector.DposSelector
	miner    *miner.DposMiner
	checker  *checker.DposChecker

	baseClient *common.BaseClient
}

// NewDpos 新建一个dpos共识模块
func NewDpos() common.ConsensusModule {
	m := &Module{}
	m.baseClient = common.NewBaseClient()
	m.selector = selector.NewSelector(m.GetBaseClient())
	m.miner = miner.NewMiner(m.GetBaseClient())
	m.checker = checker.NewChecker(m.GetBaseClient())
	moduleStartupFunc := func(startedInterestedModules map[string][]*registry.ModRegKV) error {
		dposcommon.Initialize(m.GetBaseClient())
		conType := m.baseClient.GetCurParam().GetConsensus().GetType()
		switch conType {
		case protosconfig.SoloConsensusType:
		case protosconfig.DposConsensusType:
			m.baseClient.StartEventLoop()
			m.selector.Start(m.RootCtx, m.Config, m.Log)
			m.miner.Start(m.RootCtx, m.Config, m.Log)
			m.checker.Start(m.RootCtx, m.Config, m.Log)
			m.baseClient.SetCurrentCon(m)
			m.baseClient.SetModuleCfg(m.Config)
		}
		return nil
	}
	m.baseClient.InitParam()
	m.Init(module.ConsensusModuleName, nil, moduleStartupFunc)

	return m
}

// IsMasterStandbyMode 准备状态检查
func (m *Module) IsMasterStandbyMode() bool {
	return false
}

// Shutdown ...
func (m *Module) Shutdown() (module.Status, error) {
	m.RootCtxCancelFunc()
	return module.StatusDown, nil
}

// GetBaseClient get 共识模块公共Client
func (m *Module) GetBaseClient() *common.BaseClient {
	return m.baseClient
}

// SetBaseClient set 共识模块公共Client
func (m *Module) SetBaseClient(client *common.BaseClient) {
	m.baseClient = client
}
